//=============================================================================
/**
 * @file	gym_ghost.c
 * @brief	ゴーストジムギミック
 * @author	Nozomu Saito
 *
 * モジュール名：GYM_
 */
//=============================================================================
#include "common.h"
#include "fieldsys.h"
#include "fieldmap_work.h"
#include "system/snd_tool.h"
#include "include/savedata/gimmickwork.h"
#include "../fielddata/build_model/build_model_id.h"

#include "field_gimmick_def.h"
#include "sysflag_def.h"

#include "gym_def.h"

#include "gym_local.h"
#include "gym_init.h"

#include "gym.h"

#include "script.h"


#define GHOST_TRAINER_MAX	(4)
#define SPOT_LIGHT_Y_OFS	(0*FX32_ONE)
#define GHOST_LIGHT_SCALE	(4)

#define GHOST_PRO_MAT_Z_OFS	(256)

#define LIGHT_VANISH_WAIT	(30)

typedef struct GHOST_GYM_TEMP_WORK_tag
{
	int Light[GHOST_TRAINER_MAX];
	int TargetLight;
	TCB_PTR	LightMoveTcb;
	FIELD_OBJ_PTR TargetFldObj;
}GHOST_GYM_TEMP_WORK;

typedef struct {
	int Seq;
	int Scale;
	int VanishWait;
	FIELDSYS_WORK *fsys;
}EVENT_GYM_WORK;

const int LightTarget[GHOST_TRAINER_MAX] = {
	2,3,4,5
};		//対象ライトのOBJID

static void MoveLightTask(TCB_PTR tcb, void *work);
static BOOL VanishLight(GMEVENT_CONTROL * event);
static u8 GetLightIdx(FIELD_OBJ_PTR fldobj);
static void FogOff(FIELDSYS_WORK *fsys);

//---------------------------------------------------------------------------
/**
 * @brief	ゴーストジム:セットアップ
 *
 * @param	fsys	フィールドシステムポインタ
 *
 * @return	none
 */
//---------------------------------------------------------------------------
void GYM_SetupGhostGym(FIELDSYS_WORK *fsys)
{
	int i;
	GHOST_GYM_TEMP_WORK *ghost_temp;
	GIMMICKWORK *work;
	GHOST_GYM_WORK *ghost_gym_work;
	work = SaveData_GetGimmickWork(GameSystem_GetSaveData(fsys));
	ghost_gym_work = (GHOST_GYM_WORK*)GIMMICKWORK_Get(work, FLD_GIMMICK_GHOST_GYM);

	//ゴーストジム専用ワークをアロケートして、フィールドマップ汎用ワークポインタにあてる
	fsys->fldmap->Work = sys_AllocMemory(HEAPID_FIELD, sizeof(GHOST_GYM_TEMP_WORK));
	//初期化
	MI_CpuClear8(fsys->fldmap->Work, sizeof(GHOST_GYM_TEMP_WORK));
	ghost_temp = (GHOST_GYM_TEMP_WORK *)fsys->fldmap->Work;

	//プロジェクションマトリックス変更値の変更
	fsys->ProjOfs = GHOST_PRO_MAT_Z_OFS;

	//フォグセット
	SetFogData(fsys->fog_data, FOG_SYS_ALL,
			TRUE, GX_FOGBLEND_COLOR_ALPHA, GX_FOGSLOPE_0x0020, 0x0000);
	SetFogColor(fsys->fog_data, FOG_SYS_ALL, GX_RGB(0,0,0), 31);
	{
		int i;
		char fog_tbl[32];
		for(i=0;i<32;i++){
			fog_tbl[i] = 0xff;
		}
		SetFogTbl(fsys->fog_data, fog_tbl);
	}

	//存在しているフィールドOBJのフォグ適用をオフにする
	FogOff(fsys);
	//トレーナー数分ループ
	for(i=0;i<GHOST_TRAINER_MAX;i++){
		FIELD_OBJ_PTR fldobj_ptr;
		VecFx32 vec;
		//トレーナーIDからトレーナーの位置を取得
		fldobj_ptr = FieldOBJSys_OBJIDSearch( fsys->fldobjsys, 2+i);
		FieldOBJ_VecPosGet( fldobj_ptr, &vec );
		//ｙを変更
		vec.y += SPOT_LIGHT_Y_OFS;
		//ライト作成
		ghost_temp->Light[i] = M3DO_SetMap3DObjExp(	fsys->Map3DObjExp,
													BMID_ROOM_GYM04SPOT,
													&vec, NULL,
													fsys->field_3d_anime );
		//ギミックワークから、ライトが必要かをチェック
		if (ghost_gym_work->LightOff[i]){
			M3DO_PTR obj;
			obj = M3DO_GetMap3DObjData(fsys->Map3DObjExp, ghost_temp->Light[i]);
			M3DO_SetVanish(obj, TRUE);
			//イタコろうそく消えたグラフィックに変更
///			FieldOBJ_BlActDummyDrawReset( fldobj_ptr, ITAKO2 );

		}
	}
}

//---------------------------------------------------------------------------
/**
 * @brief	ゴーストジム:終了処理
 *
 * @param	fsys	フィールドシステムポインタ
 *
 * @return	none
 */
//---------------------------------------------------------------------------
void GYM_EndGhostGym(FIELDSYS_WORK *fsys)
{
	GHOST_GYM_TEMP_WORK *ghost_temp;
	ghost_temp = (GHOST_GYM_TEMP_WORK *)fsys->fldmap->Work;
	sys_FreeMemoryEz(ghost_temp);
	fsys->fldmap->Work = NULL;
}

//---------------------------------------------------------------------------
/**
 * @brief	ゴーストジム:トレーナーの動きに合わせてライトを追従させるタスクのセット
 *
 * @param	fsys	フィールドシステムポインタ
 *
 * @return	none
 */
//---------------------------------------------------------------------------
void GYM_SetLightMoveTask(FIELDSYS_WORK *fsys)
{
	int obj_id;
	u8 light_idx;
	FIELD_OBJ_PTR *fldobj;

	GHOST_GYM_TEMP_WORK *ghost_temp;
#if 0
	//ギミックワークを見る
	{
		int id;
		GIMMICKWORK *work;
		//ギミックワーク取得
		work = SaveData_GetGimmickWork(GameSystem_GetSaveData(fsys));
		//ギミックコードを取得
		id = GIMMICKWORK_GetAssignID(work);
		if (id != FLD_GIMMICK_GHOST_GYM){
			return;					//ゴーストジムギミック無し
		}
	}
#endif
	ghost_temp = (GHOST_GYM_TEMP_WORK *)fsys->fldmap->Work;

	fldobj = GetEvScriptWorkMemberAdrs( fsys, ID_EVSCR_TR0_FLDOBJ );

	light_idx = GetLightIdx(*fldobj);

	if (light_idx == GHOST_TRAINER_MAX){
		GF_ASSERT(0);
		return;
	}

	ghost_temp->TargetLight = light_idx;
	ghost_temp->TargetFldObj = *fldobj;
	ghost_temp->LightMoveTcb = TCB_Add(MoveLightTask, fsys, 0);
	//↑TCB作成（フィールドOBJより速く処理されるようにプライオリティを決定する）
}

//---------------------------------------------------------------------------
/**
 * @brief	ゴーストジム:トレーナーの動きに合わせてライトを追従させるタスクの削除
 *
 * @param	fsys	フィールドシステムポインタ
 *
 * @return	none
 */
//---------------------------------------------------------------------------
void GYM_DelLightMoveTask(FIELDSYS_WORK *fsys)
{
	GHOST_GYM_TEMP_WORK *ghost_temp;
#if 0
	//ギミックワークを見る
	{
		int id;
		GIMMICKWORK *work;
		//ギミックワーク取得
		work = SaveData_GetGimmickWork(GameSystem_GetSaveData(fsys));
		//ギミックコードを取得
		id = GIMMICKWORK_GetAssignID(work);
		if (id != FLD_GIMMICK_GHOST_GYM){
			return;					//ゴーストジムギミック無し
		}
	}
#endif
	ghost_temp = (GHOST_GYM_TEMP_WORK *)fsys->fldmap->Work;

	TCB_Delete(ghost_temp->LightMoveTcb);
}


//---------------------------------------------------------------------------
/**
 * @brief	ゴーストジム:トレーナーのライトを消すアニメーションイベント
 *
 * @param	fsys	フィールドシステムポインタ
 * @param	inID	スクリプトワークアドレスID
 * 		ID_EVSCR_TR0_FLDOBJ:視線
 * 		ID_EVSCR_TARGET_OBJ:話しかけ
 *
 * @return	none
 */
//---------------------------------------------------------------------------
void GYM_SetVanishLightEvt(FIELDSYS_WORK *fsys, const int inID)
{
	FIELD_OBJ_PTR *fldobj;
	EVENT_GYM_WORK * egw;
	GHOST_GYM_TEMP_WORK *ghost_temp;
#if 0
	//ギミックワークを見る
	{
		int id;
		GIMMICKWORK *work;
		//ギミックワーク取得
		work = SaveData_GetGimmickWork(GameSystem_GetSaveData(fsys));
		//ギミックコードを取得
		id = GIMMICKWORK_GetAssignID(work);
		if (id != FLD_GIMMICK_GHOST_GYM){
			return;					//ゴーストジムギミック無し
		}
	}
#endif
	ghost_temp = (GHOST_GYM_TEMP_WORK *)fsys->fldmap->Work;

	fldobj = GetEvScriptWorkMemberAdrs( fsys, inID );
	ghost_temp->TargetLight = GetLightIdx(*fldobj);
	ghost_temp->TargetFldObj = *fldobj;

	//イベントコール
	egw = sys_AllocMemoryLo(HEAPID_WORLD, sizeof(EVENT_GYM_WORK));
	egw->Seq = 0;
	egw->Scale = 1;
	egw->VanishWait = 0;
	egw->fsys = fsys;

	FieldEvent_Call(fsys->event, VanishLight, egw);
}

//---------------------------------------------------------------------------
/**
 * @brief	ライト動くタスク
 *
 * @param	tcb		TCB
 * @param	work	ワークポインタ
 *
 * @return	none
 */
//---------------------------------------------------------------------------
static void MoveLightTask(TCB_PTR tcb, void *work)
{
	FIELD_OBJ_PTR fldobj_ptr;
	GHOST_GYM_TEMP_WORK *ghost_temp;
	FIELDSYS_WORK *fsys = (FIELDSYS_WORK *)work;

	ghost_temp = (GHOST_GYM_TEMP_WORK *)fsys->fldmap->Work;
	//対象フィールドOBJの位置を取得
	{
		VecFx32 vec;
		M3DO_PTR obj;
		FieldOBJ_VecPosGet( ghost_temp->TargetFldObj, &vec );
		//ｙを変更
		vec.y += SPOT_LIGHT_Y_OFS;
		//ライトOBJ取得
		obj = M3DO_GetMap3DObjData(fsys->Map3DObjExp, ghost_temp->Light[ghost_temp->TargetLight]);
		//座標書き換え
		M3DO_SetGlobalVec(obj, &vec);
	}
}


//----------------------------------------------------------------------------
/**
 *	@brief	ライトを小さくするイベント
 *
 *	@param	* event		イベントポインタ
 *
 *	@return	BOOL		TRUE:終了　FALSE:継続
 */
//-----------------------------------------------------------------------------
static BOOL VanishLight(GMEVENT_CONTROL * event)
{
	M3DO_PTR obj;
	EVENT_GYM_WORK * egw = FieldEvent_GetSpecialWork(event);
	GHOST_GYM_TEMP_WORK *ghost_temp = (GHOST_GYM_TEMP_WORK *)egw->fsys->fldmap->Work;

	switch(egw->Seq){
	case 0:
		//スポットライトを消すまでのウェイト
		if (egw->VanishWait++ >= LIGHT_VANISH_WAIT){
			//ろうそく消えるＳＥ
			Snd_SePlay(SEQ_SE_GS_ROUSOKU_KIERU);
			egw->Seq++;
		}
		break;
	case 1:
		//ライトOBJ取得
		obj = M3DO_GetMap3DObjData(egw->fsys->Map3DObjExp, ghost_temp->Light[ghost_temp->TargetLight]);

		if (egw->Scale >= GHOST_LIGHT_SCALE){
			M3DO_SetVanish(obj, TRUE);
			//スポットライトオフ
			{
				GIMMICKWORK *work;
				GHOST_GYM_WORK *ghost_gym_work;
				work = SaveData_GetGimmickWork(GameSystem_GetSaveData(egw->fsys));
				ghost_gym_work = (GHOST_GYM_WORK*)GIMMICKWORK_Get(work, FLD_GIMMICK_GHOST_GYM);
				ghost_gym_work->LightOff[ghost_temp->TargetLight] = 1;
			}
			FieldOBJ_BlActDummyDrawReset( ghost_temp->TargetFldObj, ITAKO2 );
			egw->Seq++;
		}else{
			//ライトのスケールを小さくする
			egw->Scale++;
		}

		//対象フィールドOBJのスケール変更
		{
			VecFx32 *vec;

			vec = M3DO_GetScaleVecPtr(obj);
			vec->x = FX32_ONE/egw->Scale;
			vec->y = FX32_ONE/egw->Scale;
			vec->z = FX32_ONE/egw->Scale;
		}
		break;
	case 2:
		if (FieldOBJ_BlActAddPracFlagCheck(ghost_temp->TargetFldObj)==FALSE ){
			//存在しているフィールドOBJのフォグ適用をオフにする
			FogOff(egw->fsys);
			//解放
			sys_FreeMemoryEz(egw);
			return TRUE;
		}
		break;
	}
	return FALSE;
}

//----------------------------------------------------------------------------
/**
 *	@brief	ライトのインデックス取得
 *
 *	@param	fldobj
 *
 *	@return	u8	ライトインデックス
 */
//-----------------------------------------------------------------------------
static u8 GetLightIdx(FIELD_OBJ_PTR fldobj)
{
	u8 i;
	int obj_id;
	//OBJID取得
	obj_id = FieldOBJ_OBJIDGet( fldobj );
	//対象ライトインデックス取得
	for(i=0;i<GHOST_TRAINER_MAX;i++){
		if (obj_id == LightTarget[i]){
			break;
		}
	}
	return i;
}

//----------------------------------------------------------------------------
/**
 *	@brief	ビルボードアクターのフォグをオフ
 *
 *	@param	fsys		フィールドシステムポインタ
 *
 *	@return none
 */
//-----------------------------------------------------------------------------
static void FogOff(FIELDSYS_WORK *fsys)
{
	int i;
	int max;
	FIELD_OBJ_PTR fldobj;
	max = FieldOBJSys_OBJMaxGet( fsys->fldobjsys );
	fldobj = FieldOBJSys_FldOBJWorkGet( fsys->fldobjsys );
	for(i=0;i<max;i++){
		if( FieldOBJ_StatusBitCheck_Use(fldobj) == TRUE ){
			BLACT_WORK_PTR blact_ptr = FieldOBJ_DrawBlAct00_BlActPtrGet( fldobj );
			NNS_G3dMdlSetMdlFogEnableFlagAll( BLACT_MdlResGet(blact_ptr), FALSE );
		}
		FieldOBJSys_FldOBJWorkInc( &fldobj );
	}
}